package com.example.tests;

import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.AssertJUnit;
import static org.hamcrest.Matchers.equalTo;

import java.io.FileReader;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;

import org.apache.commons.lang.RandomStringUtils;
import org.junit.Assert;
import org.testng.annotations.*;
import com.example.data.ContactData;
import com.example.data.GroupData;
import com.example.framework.ApplicationManager;

public class TestBase {

	protected ApplicationManager manager;
	private Logger log = Logger.getLogger("TEST");

	@BeforeClass  //why not BeforeTest(NullPointerException)? Vopros dlya konsultazii
	@Parameters({"configFile"})
	public void setUp(@Optional String configFile) throws Exception {
		if (configFile == null) {
			configFile = System.getProperty("configFile");
			//set some default value for filename
		}
		if (configFile == null) {
			configFile = System.getenv("configFile");
		}
		if (configFile == null) {
			configFile = "application.properties";
		}

		Properties properties = new Properties();
		properties.load(new FileReader(configFile));
		log.info("@BeforeClass setUp starting");
		System.out.println("Run @BeforeClass method.");
		manager = ApplicationManager.getInstance();
		manager.setProperties(properties);
		log.info("setUp ending");
	}

	@AfterTest //Why not AfterClass?
	public void tearDown() throws Exception {
		log.info("@AfterTest tearDown starting");
		System.out.println("Run @AfterTest method.");
		ApplicationManager.getInstance().stop();
		log.info("@AfterTest tearDown ending");
	}	

	public String generateRandomString(int length) {
		return RandomStringUtils.randomAlphanumeric(length);
	}

	public static String generateAlphaNumbericRandom(int length) {
		String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
		int numberOfCodes = 0;
		String code = "";
		while (numberOfCodes < length) {
			char c = chars.charAt((int) (Math.random() * chars.length()));
			code += c;
			numberOfCodes++;
		}
		return code;
	}

	@BeforeTest
	public void BeforeTest()
	{
		log.info("Run @BeforeTest method.");
	}

	@AfterTest
	public void AfterTest()
	{
		log.info("Run @AfterTest method.");
	}

	@AfterClass
	public void AfterClass()
	{
		log.info("Run @AfterClass method.");
	}

	@BeforeSuite
	public void BeforeSuite()
	{
		log.info("Run @BeforeSuite method.");
	}
	@AfterSuite
	public void AfterSuite()
	{
		log.info("Run @AfterSuite method.");
	}

	protected void verifyGroupAdded(Set<GroupData> oldList, GroupData group, Set<GroupData> newList) {
		AssertJUnit.assertEquals(newList.size(), oldList.size() + 1);//traditional testng/junit version
		//set id = $$$ in order group to be added in list
		group.setId("$$$");
		oldList.add(group);
		group.setId(null);		
		AssertJUnit.assertEquals(oldList, newList);
	}

	protected void verifyGroupChanged(Set<GroupData> oldList, GroupData groupToModify, GroupData newGroup,
			Set<GroupData> newList) throws InterruptedException {
		Assert.assertThat(newList.size(), equalTo(oldList.size()));
		GroupData groupToRemove = groupToModify;

		oldList.remove(groupToRemove);
		newGroup.setId("$$$");
		oldList.add(newGroup);
		newGroup.setId(null);	
		AssertJUnit.assertEquals(oldList, newList);

	}

	protected void verifyGroupDeleted(Set<GroupData> oldList, GroupData groupToDelete, Set<GroupData> newList) {
		Assert.assertThat(newList.size(), equalTo(oldList.size()-1));
		oldList.remove(groupToDelete);
		AssertJUnit.assertEquals(oldList, newList);
	}

	protected void verifyContactAdded(Set<ContactData> oldList, ContactData contact, Set<ContactData> newList) {
		AssertJUnit.assertEquals(newList.size(), oldList.size() + 1);//traditional testng/junit version
		//set id = $$$ in order group to be added in list
		contact.setId("$$$");
		oldList.add(contact);
		contact.setId(null);
		AssertJUnit.assertEquals(oldList, newList);

	}

	protected void verifyContactChanged(Set<ContactData> oldList, ContactData contactToModify,
			ContactData newContact, Set<ContactData> newList) {
		Assert.assertThat(newList.size(), equalTo(oldList.size()));
		ContactData contactToRemove = contactToModify;
		oldList.remove(contactToRemove);
		newContact.setId("$$$");
		oldList.add(newContact);
		newContact.setId(null);	
		AssertJUnit.assertEquals(oldList, newList);
	}

	protected void verifyContactRemoved(Set<ContactData> oldList, ContactData contactToDelete, Set<ContactData> newList) {
		Assert.assertThat(newList.size(), equalTo(oldList.size()-1));
		oldList.remove(contactToDelete);
		AssertJUnit.assertEquals(oldList, newList);

	}
}
